package dao;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class DBOperation<T> {
	private Class<T> entity;
	private String tableName;
	private Method m;
	private Field[] fd;

	@SuppressWarnings("unchecked")
	public DBOperation() {
		// TODO Auto-generated constructor stub
		ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
		entity = (Class<T>) type.getActualTypeArguments()[0];
		tableName = entity.getSimpleName();
		fd = entity.getDeclaredFields();
		System.out.println(type + "\t");
		System.out.println(entity + "\t");
		System.out.println(tableName);
	}

	public void insert(T o) {
		StringBuffer sql = new StringBuffer("insert into " + tableName + "(");
		for (int i = 0; i < fd.length; i++) {
			sql.append(fd[i].getName());
			if (i < fd.length - 1)
				sql.append(",");
			else
				sql.append(") values(");
		}

		for (int i = 0; i < fd.length; i++) {
			sql.append("?");
			if (i < fd.length - 1)
				sql.append(",");
			else
				sql.append(")");
		}
		try {
			PreparedStatement pstm = DBUtil.getCon().prepareStatement(sql.toString());
			for (int i = 0; i < fd.length; i++) {
				fd[i].setAccessible(true);
				Object val = fd[i].get(o);
				pstm.setObject(i + 1, val);
			}
			pstm.executeUpdate();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public List<T> select() {
		List<T> list = new ArrayList<>();
		list.clear();
		String sql = "select * from " + tableName + " order by id";
		try {
			Statement stm = DBUtil.getCon().createStatement();
			ResultSet rs = stm.executeQuery(sql);
			while (rs.next()) {
				T object = entity.newInstance();
				Method[] md = object.getClass().getDeclaredMethods();
				for (int i = 0; i < md.length; i++) {
					String methodName = md[i].getName();
					Parameter[] pt = md[i].getParameters();
					if (methodName.indexOf("set") != -1) {
						String subName = methodName.substring(3, methodName.length()).toLowerCase();
						for (int j = 0; j < pt.length; j++) {
							if (pt[j].getType().getSimpleName().indexOf("Integer") != -1) {
								m = object.getClass().getDeclaredMethod(methodName, Integer.class);
								m.invoke(object, rs.getInt(subName));
								break;
							} else {
								m = object.getClass().getDeclaredMethod(methodName, String.class);
								m.invoke(object, rs.getString(subName));
								break;
							}
						}
					}
				}
				list.add(object);
			}
			return list;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}

	public void update(T o, Integer id) {
		StringBuffer sql = new StringBuffer("update " + tableName + " set ");
		for (int i = 0; i < fd.length; i++) {
			fd[i].setAccessible(true);
			if (fd[i].getName().toString().toLowerCase().indexOf("id") == -1) {
				try {
					sql.append(fd[i].getName() + "=?");
					if (i < fd.length - 1)
						sql.append(",");
					else
						sql.append(" where ");
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		for (int i = 0; i < fd.length; i++) {
			fd[i].setAccessible(true);
			if (fd[i].getName().toString().toLowerCase().indexOf("id") != -1) {
				sql.append(fd[i].getName() + "=" + id);
			}
		}

		int count = 0;
		try {
			PreparedStatement pstm = DBUtil.getCon().prepareStatement(sql.toString());
			for (int i = 0; i < fd.length; i++) {
				fd[i].setAccessible(true);
				if (fd[i].getName().toString().toLowerCase().indexOf("id") != -1) {

				} else {
					count++;
					Object val = fd[i].get(o);
					pstm.setObject(count, val);
				}
			}

			count = 0;
			pstm.executeQuery();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	int counter = 0;

	public void delete(T o) {
		StringBuffer sql = new StringBuffer("delete from " + tableName + " where ");
		for (int i = 0; i < fd.length; i++) {
			fd[i].setAccessible(true);
			try {
				if (fd[i].get(o) != null) {
					if (fd[i].getType().getSimpleName().indexOf("Integer") != -1) {
						counter++;
						if (counter <= 1) {
							try {
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + fd[i].get(o));
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						} else {
							try {
								sql.append(" AND ");
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + fd[i].get(o));
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					} else {
						counter++;
						if (counter <= 1) {
							try {
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + "\'" + fd[i].get(o) + "\'");
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						} else {
							try {
								sql.append(" AND ");
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + "\'" + fd[i].get(o) + "\'");
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}

			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		counter = 0;
		System.out.println(sql.toString());
		try {
			Statement stm = DBUtil.getCon().createStatement();
			stm.executeQuery(sql.toString());
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return;
		}
	}

	int counter1 = 0;

	public List<T> singleSelect(T o) {
		List<T> list = new ArrayList<>();
		list.clear();
		StringBuffer sql = new StringBuffer("select * from " + tableName + " where ");
		for (int i = 0; i < fd.length; i++) {
			fd[i].setAccessible(true);
			try {
				if (fd[i].get(o) != null) {
					if (fd[i].getType().getSimpleName().indexOf("Integer") != -1) {
						counter1++;
						if (counter1 <= 1) {
							try {
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + fd[i].get(o));
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						} else {
							try {
								sql.append(" AND ");
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + fd[i].get(o));
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					} else {
						counter1++;
						if (counter1 <= 1) {
							try {
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + "\'" + fd[i].get(o) + "\'");
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						} else {
							try {
								sql.append(" AND ");
								sql.append(fd[i].getName().toString().toLowerCase() + "=" + "\'" + fd[i].get(o) + "\'");
							} catch (IllegalArgumentException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}

			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		sql.append(" order by id");
		counter1 = 0;
		System.out.println(sql.toString());
		try {
			Statement stm = DBUtil.getCon().createStatement();
			ResultSet rs = stm.executeQuery(sql.toString());
			while (rs.next()) {
				T object=(T) o.getClass().newInstance();
				Method[] md = o.getClass().getDeclaredMethods();
				for (int i = 0; i < md.length; i++) {
					md[i].setAccessible(true);
					if (md[i].getName().contains("set")) {
						Parameter pa = md[i].getParameters()[0];
						String methodName = md[i].getName();
						String subName = methodName.substring(3, methodName.length());
						if (pa.getType().getSimpleName().indexOf("Integer") != -1) {
							Method m = object.getClass().getDeclaredMethod(methodName, Integer.class);
							m.invoke(object, rs.getInt(subName));
						} else {
							Method m = object.getClass().getDeclaredMethod(methodName, String.class);
							m.invoke(object, rs.getString(subName));
						}
					}
				}
				list.add(object);
			}
			return list;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			return null;
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			return null;
		}
	}
}
